﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.Toolbox.Collections;
using System.ComponentModel;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Feeds.Finance.MarketData;

namespace Algobox.Structure.Finance.Strategies.FractionPrototype
{
    public class FractionComponentOpen : Strategy, IFractionComponent, INotifyPropertyChanged, IMarketUpdateLast, IMarketUpdateOpen
    {
        public FractionComponentOpen(
            Guid databaseId,
            FractionManagement manager,
            StockSecurity securityA,
            StockSecurity securityB)
            :base(securityA, securityB)
        {

            _databaseId = databaseId;
            Manager = manager;

            manager.MarketFeed.SubscribeLast(securityA, this);
            manager.MarketFeed.SubscribeLast(securityB, this);
            manager.MarketFeed.SubscribeOpen(securityA, this);
            manager.MarketFeed.SubscribeOpen(securityB, this);
            
            LOG.Info("{0}|{1}:{2}|FractionComponentOpen with DatabaseId({3})", _strategyIdString, securityA, securityB, databaseId);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        
        private static readonly NLog.Logger LOG = NLog.LogManager.GetCurrentClassLogger();
        
        private Guid _databaseId;
        private bool _isEnabled;
        private double _moveOpenA;
        private double _moveOpenB;
        private double _diffOpen;
        private ushort _value = 0;
        private double _trigger = 0;
        private double _exit = 0;

        private FractionTrigger _leg;

        public FractionManagement Manager { get; set; }

        public bool IsLoaded { get; private set; }
        public bool IsStarted { get; private set; }

        public Guid DatabaseId { get { return _databaseId; } }
        public bool IsTriggered { get { return _leg != null; } }
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                if (value)
                {
                    if (_trigger == 0 || _value == 0)
                    {
                        _isEnabled = false;
                    }
                    // or do other start up checks here
                    else
                    {
                        _isEnabled = true;
                    }
                }
                else
                {
                    // diable stuff here
                    _isEnabled = false;
                }
                NotifyPropertyChanged("IsEnabled");
            }
        }
        public string SymbolA
        {
            get { return _security.Symbol; }
            set
            {

                if (!String.IsNullOrWhiteSpace(value))
                {
                    Manager.MarketFeed.UnsubscribeLast(_security, this);
                    Manager.MarketFeed.UnsubscribeOpen(_security, this);
                    _security = Manager.Data.AddStock(value);
                    Manager.MarketFeed.SubscribeLast(_security, this);
                    Manager.MarketFeed.SubscribeOpen(_security, this);
                    NotifyPropertyChanged("SymbolA");
                }
            }
        }
        public string SymbolB
        {
            get { return _securityPair.Symbol; }
            set
            {

                if (!String.IsNullOrWhiteSpace(value))
                {
                    Manager.MarketFeed.UnsubscribeLast(_securityPair, this);
                    Manager.MarketFeed.UnsubscribeOpen(_securityPair, this);
                    _securityPair = Manager.Data.AddStock(value);
                    Manager.MarketFeed.SubscribeLast(_securityPair, this);
                    Manager.MarketFeed.SubscribeOpen(_securityPair, this);
                    NotifyPropertyChanged("SymbolB");
                }
            }
        }
        public double CloseA
        {
            get { return _security.Prices.OHLC.Close; }
            set { NotifyPropertyChanged("CloseA"); }
        }
        public double CloseB
        {
            get { return _securityPair.Prices.OHLC.Close; }
            set { NotifyPropertyChanged("CloseB"); }
        }
        public double OpenA
        {
            get { return _security.Prices.OHLC.Open; }
            set { NotifyPropertyChanged("OpenA"); }
        }
        public double OpenB
        {
            get { return _securityPair.Prices.OHLC.Open; }
            set { NotifyPropertyChanged("OpenB"); }
        }
        public double OpenMoveA
        {
            get { return _moveOpenA * 100; }
            set { _moveOpenA = value; NotifyPropertyChanged("OpenMoveA"); }
        }
        public double OpenMoveB
        {
            get { return _moveOpenB * 100; }
            set { _moveOpenB = value; NotifyPropertyChanged("OpenMoveB"); }
        }
        public double OpenDifference
        {
            get { return _diffOpen * 100; }
            private set { _diffOpen = value; NotifyPropertyChanged("OpenDifference"); }
        }
        public ushort Value
        {
            get { return _value; }
            set 
            { 
                if(value <= UInt16.MaxValue) 
                    _value = value; 
                NotifyPropertyChanged("Value"); 
            }
        }
        public double Trigger
        {
            get { return _trigger; }
            set
            {
                if (value > 0 && value <= 100)
                {
                    _trigger = value;
                    if (_trigger <= _exit)
                        Exit = 0;
                }
                NotifyPropertyChanged("Trigger");
            }
        }
        public double Exit
        {
            get { return _exit; }
            set
            {
                if (value > 0 && value <= 100 && _exit < _trigger)
                {
                    _exit = value;
                }
                NotifyPropertyChanged("Exit");
            }
        }
    
        void  IMarketUpdateLast.OnPriceLast(IStock stock, Objects.Finance.Prices.PriceVolume last)
        {            
            if (stock == _security)
            {
                if (_moveOpenA == 0)
                {
                    OpenMoveA = (_security.Prices.OHLC.Open - _security.Prices.OHLC.Close) / _security.Prices.OHLC.Close;
                    OpenDifference = _moveOpenA - _moveOpenB;
                    
                    NotifyPropertyChanged("CloseA");
                    NotifyPropertyChanged("OpenA");
                }
            }
            else if (stock == _securityPair)
            {
                if (_moveOpenB == 0)
                {
                    OpenMoveB = (_securityPair.Prices.OHLC.Open - _securityPair.Prices.OHLC.Close) / _securityPair.Prices.OHLC.Close;
                    OpenDifference = _moveOpenA - _moveOpenB;
                    
                    NotifyPropertyChanged("CloseB");
                    NotifyPropertyChanged("OpenB");
                }
            }
        }


        void IMarketUpdateOpen.OnPriceOpen(IStock stock, double openPrice, int openInterest)
        {
            if (stock == _security)
            {
                OpenMoveA = (_security.Prices.OHLC.Open - _security.Prices.OHLC.Close) / _security.Prices.OHLC.Close;
                OpenDifference = _moveOpenA - _moveOpenB;

                CheckTriggerOpen();

                NotifyPropertyChanged("CloseA");
                NotifyPropertyChanged("OpenA");
            }
            else if (stock == _securityPair)
            {
                OpenMoveB = (_securityPair.Prices.OHLC.Open - _securityPair.Prices.OHLC.Close) / _securityPair.Prices.OHLC.Close;
                OpenDifference = _moveOpenA - _moveOpenB;

                CheckTriggerOpen();

                NotifyPropertyChanged("CloseB");
                NotifyPropertyChanged("OpenB");
            }
        }


        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private bool CheckTriggerOpen()
        {
            if (!_isEnabled)
                return false;

            if (_trigger == 0)
                return false;

            if (_leg != null)
                return false;

            if (Math.Abs(_diffOpen) * 100 > _trigger)
            {
                _leg = new FractionTrigger(this);
                Manager.TryAddTrigger(Guid.NewGuid(), _leg);
                NotifyPropertyChanged("IsTriggered");
                return true;
            }
            return false;
        }


        public void OnFractionTriggerComplete(FractionTrigger leg)
        {
            if (_leg == leg)
            {
                _leg = null;
                NotifyPropertyChanged("IsTriggered");
            }
        }
    }
}
